package com.brackets;

import com.brackets.exceptions.ExecuteException;

/**
 * @author sad
 */
public class Variable {

    public enum VarType {

        STRING, INT, FLOAT
    }
    private long valueL;
    private double valueD;
    private String valueS;
    private VarType type = VarType.INT;

    public Variable() {
    }

    public Variable(long value) {
        type = VarType.INT;
        valueL = value;
    }

    public Variable(int value) {
        type = VarType.INT;
        valueL = value;
    }

    public Variable(String value) {
        type = VarType.STRING;
        valueS = value;
    }

    public Variable(double value) {
        type = VarType.FLOAT;
        valueD = value;
    }

    public long getValueLong() {
        if(type==VarType.FLOAT){
            return (long)valueD;
        }
        return valueL;
    }

    public double getValueDouble() {
        if(type==VarType.INT){
            return (double)valueL;
        }
        return valueD;
    }

    public String getValueString() {
        return toString();
    }

    public VarType getType() {
        return type;
    }

    public void set(String value) {
        type = VarType.STRING;
        valueS = value;
    }

    public void set(long value) {
        type = VarType.INT;
        valueL = value;
    }

    public void set(double value) {
        type = VarType.FLOAT;
        valueD = value;
    }

    public Variable add(Variable v) {
        switch (type) {
            case STRING:
                return new Variable(valueS+v.toString());
            case INT:
                return new Variable(valueL+v.getValueLong());
            case FLOAT:
                return new Variable(valueD+v.getValueDouble());
        }
        throw new IllegalArgumentException();
    }
    
    public Variable minus(Variable v) {
        switch (type) {
            case STRING:
                throw new ExecuteException("Cannot subtract from String");
            case INT:
                return new Variable(valueL-v.getValueLong());
            case FLOAT:
                return new Variable(valueD-v.getValueDouble());
        }
        throw new IllegalArgumentException();
    }
    
    public Variable multiple(Variable v) {
        switch (type) {
            case STRING:
                throw new ExecuteException("Cannot multiple String");
            case INT:
                return new Variable(valueL*v.getValueLong());
            case FLOAT:
                return new Variable(valueD*v.getValueDouble());
        }
        throw new IllegalArgumentException();
    }
    
    public Variable div(Variable v) {
        switch (type) {
            case STRING:
                throw new ExecuteException("Cannot divide String");
            case INT:
                return new Variable(valueL/v.getValueLong());
            case FLOAT:
                return new Variable(valueD/v.getValueDouble());
        }
        throw new IllegalArgumentException();
    }
    
    public Variable eq(Variable v) {
        switch (type) {
            case STRING:
                return new Variable(isEqual(valueS, v.getValueString())?1:0);
            case INT:
                return new Variable(valueL==v.getValueLong()?1:0);
            case FLOAT:
                return new Variable(valueD==v.getValueDouble()?1:0);
        }
        throw new IllegalArgumentException();
    }
    
    public Variable moreThan(Variable v) {
        switch (type) {
            case STRING:
                if(valueS==null){
                    return new Variable(0);
                }

                return new Variable(valueS.compareTo(v.getValueString())>0?1:0);
            case INT:
                return new Variable(valueL>v.getValueLong()?1:0);
            case FLOAT:
                return new Variable(valueD>v.getValueDouble()?1:0);
        }

        throw new IllegalArgumentException();
    }
    
    public Variable lessThan(Variable v) {
        switch (type) {
            case STRING:
                if(valueS==null){
                    return new Variable(0);
                }

                return new Variable(valueS.compareTo(v.getValueString())<0?1:0);
            case INT:
                return new Variable(valueL<v.getValueLong()?1:0);
            case FLOAT:
                return new Variable(valueD<v.getValueDouble()?1:0);
        }

        throw new IllegalArgumentException();
    }
    
    private boolean isEqual(Object obj, Object obj2){
        if(obj==obj2)return true;
        if((obj!=null&& obj2==null)||(obj==null&& obj2!=null)){
            return false;
        }
        return obj.equals(obj);
    }

    public Object getValue() {
        switch (type) {
            case FLOAT:
                return (Double) valueD;
            case STRING:
                return valueS;
            case INT:
                return valueL;
            default:
                return null;
        }
    }

    @Override
    public String toString() {
        Object v = getValue();
        if (v == null) {
            return "null";
        }

        return v.toString();
    }

}
